#pragma once

#include <vex/core/any_allocator.h>
#include <vex/core/implementation/memory_resource_default_impl.h>
#include <vex/core/make_intrusive_handle.h>
#include <memory>

namespace vex {
    namespace core {

        template<class TAlloc> auto make_any_allocator(TAlloc&& p_alloc)
            -> any_allocator<typename TAlloc::value_type>
        {
            try {
                return any_allocator<typename TAlloc::value_type>(
                    make_intrusive_handle<
                    implementation::memory_resource_default_impl<TAlloc>
                    >(std::forward<TAlloc>(p_alloc)));
            } catch (...) {
                return any_allocator<typename TAlloc::value_type>();
            }
        }

        template<class T> auto make_any_allocator(contract::memory_resource* p_mem_resource)
            -> any_allocator<T>
        {
            return any_allocator<T>(p_mem_resource);
        }
        template<class T> auto make_any_default_allocator()
            -> any_allocator<T>
        {
            try {
                return any_allocator<T>(core::make_intrusive_handle<
                    implementation::memory_resource_default_impl<std::allocator<T>>
                >(std::allocator<T>()));
            } catch (...) {
                return any_allocator<T>();
            }
        }

        template<class T> auto make_any_cstdlib_allocator()
            -> any_allocator<T>
        {
            try {
                return any_allocator<T>(core::make_intrusive_handle<cstdlib_memory_resource_t>(
                    implementation::cstdlib_allocator()));
            } catch (...) {
                return any_allocator<T>();
            }
        }
    }

    using core::make_any_allocator;
}